package com.xiaoma.h5testdemo.business.web.ui

import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri
import android.net.http.SslError
import android.os.Bundle
import android.os.Message
import android.os.SystemClock
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.webkit.GeolocationPermissions
import android.webkit.JsPromptResult
import android.webkit.JsResult
import android.webkit.PermissionRequest
import android.webkit.SslErrorHandler
import android.webkit.ValueCallback
import android.webkit.WebBackForwardList
import android.webkit.WebChromeClient
import android.webkit.WebHistoryItem
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.app.ActivityCompat
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.XXPermissions
import com.xiaoma.common.extend.getDrawableRes
import com.xiaoma.common.extend.hide
import com.xiaoma.common.extend.show
import com.xiaoma.common.ui.BaseFragment
import com.xiaoma.common.utils.AppHolder
import com.xiaoma.common.utils.PermissionUtil
import com.xiaoma.common.utils.ViewUtils
import com.xiaoma.h5testdemo.R
import com.xiaoma.h5testdemo.business.main.ui.XmPromptDialog
import com.xiaoma.h5testdemo.business.main.ui.XmSelectDialog
import com.xiaoma.h5testdemo.business.main.vm.HostActVm
import com.xiaoma.h5testdemo.business.web.vm.ChromeWebVm
import com.xiaoma.h5testdemo.collect.CollectMgr
import com.xiaoma.h5testdemo.common.constants.Constants
import com.xiaoma.h5testdemo.common.constants.XmPermissions
import com.xiaoma.h5testdemo.common.dialog.XmImitateDialogHelper
import com.xiaoma.h5testdemo.common.helper.WebViewCacheHolder
import com.xiaoma.h5testdemo.common.models.CollectEntity
import com.xiaoma.h5testdemo.common.models.PageEntity
import com.xiaoma.h5testdemo.common.utils.BitmapUtils
import com.xiaoma.h5testdemo.common.utils.WebViewUtils
import com.xiaoma.h5testdemo.common.widget.XmProxyChromeWebView
import com.xiaoma.h5testdemo.databinding.FragmentWebBinding
import com.xiaoma.lib.log.KLog
import com.xiaoma.lib.store.TPUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.CopyOnWriteArrayList


/**
 * author: liangjingbo
 * date: 2023/8/8
 * describe:
 */
open class ChromeWebFragment : BaseFragment<FragmentWebBinding>(FragmentWebBinding::inflate) {

    private val INVALIDATE_ERROR_CODE = -1000
    private val defaultUrl = "https://www.youtube.com"
    private var mCurrentUrl = defaultUrl
    private var mHomeUrl = defaultUrl
    private var mCurrentUserAgent = ""
    private var mMainWebView: XmProxyChromeWebView? = null
    private val mNewWebViewList = CopyOnWriteArrayList<XmProxyChromeWebView>()
    private var mFilePathCallback: ValueCallback<Array<Uri?>>? = null

    private var mGeolocationCallback: GeolocationPermissions.Callback? = null
    private var locationPermissionUrl: String? = null
    private var mCurrentPageEntity: PageEntity? = null
    private val mDefaultPageEntity = PageEntity(
        "https://www.baidu.com",
        Constants.SOCIAL_USER_AGENT,
        1, 1, true)
    private var mFailingUrl: String? = null
    private var mFailingWebView: WebView? = null
    private var mIsLoadFailure = false
    private var mIsNetError = false
    private var mCustomViewCallback: WebChromeClient.CustomViewCallback? = null
    protected lateinit var mImitateDialogHelper: XmImitateDialogHelper
    private var isFullScreen = false

    private val mHostVm by activityViewModels<HostActVm>()
    private val mChromeWebVm by viewModels<ChromeWebVm>()
    private var mErrorIconRes = R.drawable.icon_load_error
    private var hasLoaded = false
    private val DISABLE_ALPHA = 120
    private val ENABLE_ALPHA = 255


    private val mLaunchActivityForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()
    ) { activityResult ->
        try {
            handleActivityResult(activityResult)
        } catch (e: Exception) {
            e.printStackTrace()
            KLog.e(TAG, "mLaunchActivityForResult() XM_Exception: $e")
        }
    }

    private val mRequestLocationPermission =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
            KLog.i(TAG, "mRequestLocationPermission() it:$it")
            handleRequestLocationPermission(it)
        }

    private val mWebViewClientProxyObj = object : XmProxyChromeWebView.WebViewClientProxy {
        override fun onPageFinishedProxy(view: WebView?, url: String?) {
            KLog.i(TAG, "onPageFinishedProxy() ")
            safelyHandleBackAndForwardButtonState()
            if (view == mMainWebView) {
                view?.let {
                    cacheLastUrl(it)
                }
            }
            checkContentState()
        }

        override fun onPageStartedProxy(view: WebView?, url: String?, favicon: Bitmap?) {
            KLog.i(TAG, "onPageStartedProxy() ")
            binding.urlEdit.setText(url)
            checkCollectState(view)
        }


        override fun onReceivedSslErrorProxy(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
            KLog.e(TAG, "onReceivedSslErrorProxy() error: $error")
            try {
                handleSslError(error, handler, view)
            } catch (e: Exception) {
                e.printStackTrace()
                KLog.e(TAG, "onReceivedSslErrorProxy() XM_Exception: $e")
            }
        }


        override fun onReceivedHttpErrorProxy(
            webView: WebView?, request: WebResourceRequest?, errorResponse: WebResourceResponse?
        ) {
            val forMainFrame = request?.isForMainFrame
            KLog.e(TAG, "onReceivedHttpErrorProxy() forMainFrame: $forMainFrame")
            handleReceivedError(forMainFrame, request?.url?.toString(), webView)
        }

        override fun onReceivedErrorProxy(webView: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
            val forMainFrame = request?.isForMainFrame
            KLog.e(TAG, "onReceivedErrorProxy() forMainFrame: $forMainFrame")
            if (true == forMainFrame) {
                mIsNetError = WebViewUtils.isNetErrorStatusCode(error?.errorCode ?: INVALIDATE_ERROR_CODE)
            }
            handleReceivedError(forMainFrame, request?.url?.toString(), webView)
        }

        override fun shouldOverrideUrlLoadingProxy(webView: WebView?, s: String?): Boolean {
            if (s?.endsWith(".exe") == true && webView != mMainWebView) {
                destroyNewWebView(webView)
                return true
            }
            return if (WebViewUtils.isWebViewSupportScheme(s)) {
                super.shouldOverrideUrlLoadingProxy(webView, s)
            } else {
                KLog.e(TAG, "shouldOverrideUrlLoadingProxy() url contains not support scheme ,url:$s")
                true
            }
        }

        override fun shouldOverrideUrlLoadingProxy(
            webView: WebView?, webResourceRequest: WebResourceRequest?
        ): Boolean {
            val url = webResourceRequest?.url?.toString()
            if (url?.endsWith(".exe") == true && webView != mMainWebView) {
                destroyNewWebView(webView)
                return true
            }
            return if (WebViewUtils.isWebViewSupportScheme(url)) {
                super.shouldOverrideUrlLoadingProxy(webView, url)
            } else {
                KLog.e(TAG, "shouldOverrideUrlLoadingProxy() url contains not support scheme ,url:$url")
                true
            }
        }

    }

    private fun checkCollectState(target: WebView?) {
        lifecycleScope.launch(Dispatchers.Main.immediate) {
            val collectEntity = generateCollectEntity(target)
            binding.btnCollect.isSelected = CollectMgr.isCollected(collectEntity)
        }
    }

    private suspend fun generateCollectEntity(target: WebView?): CollectEntity {
        val favicon = target?.favicon
        val bit = withContext(Dispatchers.IO) {
            BitmapUtils.bitmapToString(favicon)
        }
        val title = target?.title
        val url = getUrl(target)
        return CollectEntity(title, url, bit)
    }

    private fun handleSslError(
        error: SslError?,
        handler: SslErrorHandler?,
        view: WebView?
    ) {
        KLog.e(TAG, "handleSslError() error: $error")
        when (error?.primaryError) {
            SslError.SSL_NOTYETVALID,
            SslError.SSL_DATE_INVALID -> {
                // 直接调用proceed()继续加载页面
                handler?.proceed()
            }

            SslError.SSL_UNTRUSTED,
            SslError.SSL_EXPIRED,
            SslError.SSL_IDMISMATCH,
            SslError.SSL_INVALID -> {
                // 显示错误提示给用户
                showSSLErrorUserOptionDialog(handler, view)
            }

            else -> {
                // 其他类型的SSL错误，使用默认处理方式
                handler?.cancel()
                handleReceivedError(true, view?.url, view)
            }
        }
    }

    /**主WebViewChromeClientProxy*/
    private val mWebViewChromeClientProxyObj = object : XmProxyChromeWebView.WebViewChromeClientProxy {

        override fun onShowCustomViewProxy(view: View?, callback: WebChromeClient.CustomViewCallback?) {
            KLog.i(TAG, "onShowCustomViewProxy() view:$view ,callback：$callback")
            handleShowCustomView(view, callback)
        }

        override fun onHideCustomViewProxy() {
            KLog.i(TAG, "onHideCustomViewProxy() ")
            handleHideCustomView()
        }

        override fun onCreateWindowProxy(
            webView: WebView?, isDialog: Boolean, isUserGesture: Boolean, message: Message?
        ): Boolean {
            return handleCreateWindowProxy(webView, isDialog, isUserGesture, message)
        }

        override fun onCloseWindowProxy(webView: WebView?) {
            KLog.i(TAG, "onCloseWindowProxy() ")
            destroyNewWebView(webView)
            safelyHandleBackAndForwardButtonState()
        }

        override fun onProgressChangedProxy(view: WebView?, newProgress: Int) {
            safelyHandleBackAndForwardButtonState()
            if (newProgress == 100) {
                adapterNavigationBar(view)
                checkContentState()
                return
            }
            if (newProgress >= Constants.HIDDEN_LOADING_THRESHOLD) {
                hideLoadingView()
            }
        }

        override fun onJsAlertProxy(
            webView: WebView?,
            url: String?,
            message: String?,
            result: JsResult?
        ): Boolean {
            KLog.i(TAG, "onJsAlertProxy() ")
            showPromptDialog(message, result)
            return true
        }

        override fun onJsConfirmProxy(
            webView: WebView?,
            url: String?,
            message: String?,
            result: JsResult?
        ): Boolean {
            KLog.i(TAG, "onJsConfirmProxy() ")
            showSelectDialog(message, result)
            return true
        }

        override fun onJsBeforeUnloadProxy(
            webView: WebView?,
            url: String?,
            message: String?,
            result: JsResult?
        ): Boolean {
            KLog.i(TAG, "onJsBeforeUnloadProxy() ")
            showSelectDialog(message, result)
            return true
        }

        override fun onJsPromptProxy(
            webView: WebView?,
            url: String?,
            message: String?,
            defaultValue: String?,
            result: JsPromptResult?
        ): Boolean {
            KLog.i(TAG, "onJsAlertProxy() ")
            showPromptDialog(message, result)
            return true
        }

        override fun onShowFileChooserProxy(
            webView: WebView?, filePathCallback: ValueCallback<Array<Uri?>>?,
            fileChooserParams: WebChromeClient.FileChooserParams?
        ): Boolean {
            mFilePathCallback = filePathCallback
            openFileChooseProcess(fileChooserParams?.mode == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE)
            return true
        }

        override fun onReceivedTitleProxy(webView: WebView?, title: String?) {
            if (webView == mMainWebView) {
                webView?.let {
                    cacheLastUrl(it)
                }
            }
        }

        override fun onGeolocationPermissionsShowPromptProxy(
            origin: String?, geolocationPermissionsCallback: GeolocationPermissions.Callback?
        ) {
            activity?.let { act ->
                val permission = ActivityCompat.checkSelfPermission(act,
                    Manifest.permission.ACCESS_FINE_LOCATION)
                if (permission != PackageManager.PERMISSION_GRANTED) {
                    geolocationPermissionsCallback?.invoke(origin, true, false)
                } else {
                    locationPermissionUrl = origin
                    mGeolocationCallback = geolocationPermissionsCallback

                } ?: let {
                    KLog.e(TAG, "onGeolocationPermissionsShowPromptProxy() activity = null !! ")
                }
                mRequestLocationPermission.launch(XmPermissions.PERMISSIONS_LOCATION)
            }
        }

        override fun onPermissionRequestProxy(request: PermissionRequest?) {
            request?.resources?.let { webViewPermissions ->
                context?.let { c ->
                    try {
                        handlePermissionRequest(request, webViewPermissions, c)
                    } catch (e: Exception) {
                        e.printStackTrace()
                        KLog.e(TAG, "onPermissionRequestProxy() XM_Exception: $e")
                    }
                } ?: let { KLog.e(TAG, "onPermissionRequestProxy() context is null!!!") }
            } ?: let {
                KLog.e(TAG, "onPermissionRequestProxy() request.resources is null!!!")
            }
        }

        override fun onPermissionRequestCanceledProxy(request: PermissionRequest?) {
            super.onPermissionRequestCanceledProxy(request)
            KLog.i(TAG, "onPermissionRequestCanceledProxy() request: ${request?.resources?.joinToString()}")
        }
    }

    private fun adapterNavigationBar(view: WebView?) {
        val historyList = view?.copyBackForwardList() ?: return
        // 获取当前页面的历史记录项
        val currentIndex = historyList.currentIndex
        val currentItem = historyList.getItemAtIndex(currentIndex) ?: return
        val url = currentItem.url
        KLog.i(TAG, "adapterNavigationBar() url:$url")
        if (url?.contains("https://m.youtube.com/watch") == true
            || url?.contains("https://www.youtube.com/watch") == true) {
            hiddenNavigationBar()
        } else {
            cancelHiddenNavigationBar()
        }
    }

    private fun cancelHiddenNavigationBar() {
        lifecycleScope.launch(Dispatchers.Main) {
            val layoutParams = binding.webViewContainer.layoutParams as ConstraintLayout.LayoutParams
            layoutParams.topMargin = 0
            binding.webViewContainer.layoutParams = layoutParams
            mHostVm.cancelHiddenNavigationBar()
            setNeedMatchParent(false)
        }
    }

    private fun hiddenNavigationBar() {
        lifecycleScope.launch(Dispatchers.Main) {
            val layoutParams = binding.webViewContainer.layoutParams as ConstraintLayout.LayoutParams
            layoutParams.topMargin = resources.getDimensionPixelSize(com.xiaoma.lib.size.R.dimen.status_bar_height)
            binding.webViewContainer.layoutParams = layoutParams
            mHostVm.hiddenNavigationBar()
            setNeedMatchParent(true)
        }
    }

    override fun initView(savedInstanceState: Bundle?) {
        mImitateDialogHelper = XmImitateDialogHelper(lifecycle)
        mImitateDialogHelper.attach(requireActivity(), binding.root, savedInstanceState)
        getCurrentPageEntity()
        initWebView()
    }

    private fun getTargetWebView(): WebView? {
        if (mNewWebViewList.isNotEmpty()) {
            return mNewWebViewList.last()
        }
        return mMainWebView
    }

    override fun initEvent(savedInstanceState: Bundle?) {
        binding.loadError.tvRefresh.setOnClickListener {
            if (ViewUtils.isFastClick(1000)) return@setOnClickListener
            mIsLoadFailure = false
            mIsNetError = false
            KLog.i(TAG, "initEvent() mFailingUrl: $mFailingUrl")
            showLoading()
            mFailingUrl?.also { url ->
                mFailingWebView?.loadUrl(url)
            }
        }
        binding.urlEdit.setOnEditorActionListener { v, actionId, event ->
            if (actionId === EditorInfo.IME_ACTION_SEARCH) {
                var url: String = binding.urlEdit.editableText.toString()
                if (!url.contains("://") && !url.startsWith("javascript:")) {
                    url = "https://$url"
                }
                mIsLoadFailure = false
                destroyAllNewWeb()
                getTargetWebView()?.loadUrl(url)
                binding.urlEdit.clearFocus()
            }
            true
        }
        binding.urlEdit.setOnFocusChangeListener { v, hasFocus ->
            if (!hasFocus) {
                val inputMethodManager = requireContext().getSystemService(
                    Context.INPUT_METHOD_SERVICE) as InputMethodManager
                inputMethodManager.hideSoftInputFromWindow(v.windowToken,
                    InputMethodManager.HIDE_NOT_ALWAYS)
            }
        }
        binding.urlLoad.setOnClickListener {
            if (mMainWebView != null) {
                var url: String = binding.urlEdit.editableText.toString()
                if (!url.contains("://") && !url.startsWith("javascript:")) {
                    url = "https://$url"
                }
                mIsLoadFailure = false
                getTargetWebView()?.loadUrl(url)
            }
            binding.urlEdit.clearFocus()
        }

        binding.btnBack.setOnClickListener {
            handleWebViewGoBack()
        }
        binding.btnForward.setOnClickListener {
            handleWebViewGoForward()
        }

        binding.btnReload.setOnClickListener {
            getTargetWebView()?.reload()
        }

        binding.btnHome.setOnClickListener {
            mHostVm.goToHome()
        }
        binding.btnCollect.setOnClickListener {
            lifecycleScope.launch {
                val entity = generateCollectEntity(getTargetWebView())
                CollectMgr.handleCollect(entity){
                    checkCollectState(getTargetWebView())
                }
            }
        }
    }

    private fun loadHomePage() {
        KLog.i(TAG, "loadHomePage() ")
        loadUrl(mHomeUrl)
        showLoading()
    }

    private fun handleShowCustomView(
        view: View?,
        callback: WebChromeClient.CustomViewCallback?
    ) {
        view ?: return let {
            KLog.e(TAG, "handleShowCustomView() view is null!!!")
        }
        val fullVideoContainer = binding.flVideoContainer
        KLog.i(TAG, "handleShowCustomView() parent: ${view.parent}")
        if (view.parent != null) {
            (view.parent as ViewGroup).removeView(view)
        }
        isFullScreen = true
        mHostVm.enterFullScreen()
        setNeedMatchParent(true)
        fullVideoContainer.show()
        fullVideoContainer.addView(view)
        binding.webViewContainer.hide()
        mCustomViewCallback = callback
    }

    private fun handleHideCustomView() {
        KLog.i(TAG, "handleHideCustomView() ")
        isFullScreen = false
        mHostVm.exitFullScreen()
        binding.webViewContainer.visibility = View.VISIBLE
        binding.flVideoContainer.visibility = View.GONE
        binding.flVideoContainer.removeAllViews()
        mCustomViewCallback?.onCustomViewHidden()
        mCustomViewCallback = null
        binding.webViewContainer.hide()
        binding.webViewContainer.show()
    }

    private fun handleReceivedError(
        forMainFrame: Boolean?,
        requestUrl: String?,
        webView: WebView?) {
        KLog.i(TAG, "handleReceivedError() requestUrl:$requestUrl")
        if (forMainFrame == true) {
            mIsLoadFailure = true
            mFailingUrl = requestUrl
            mFailingWebView = webView
            checkContentState()
        }
    }

    private fun handleRequestLocationPermission(it: Map<String, @JvmSuppressWildcards Boolean>) {
        try {
            val allow = it[XmPermissions.PERMISSIONS_LOCATION[0]] ?: false
            mGeolocationCallback?.invoke(locationPermissionUrl, allow, false)
            mGeolocationCallback = null
            locationPermissionUrl = ""
        } catch (e: Exception) {
            e.printStackTrace()
            KLog.e(TAG, "handleRequestLocationPermission() XM_Exception: $e")
        }
    }

    private fun handleActivityResult(activityResult: ActivityResult?) {
        try {
            activityResult ?: return let {
                KLog.e(TAG, "handleActivityResult() activityResult is null !!!")
                mFilePathCallback?.onReceiveValue(arrayOf())
                mFilePathCallback = null
            }
            if (activityResult.resultCode != Activity.RESULT_OK) return let {
                mFilePathCallback?.onReceiveValue(arrayOf())
                mFilePathCallback = null
                KLog.e(TAG, "handleActivityResult() not result ok, activityResult:${activityResult.resultCode}")
            }
            if (mFilePathCallback == null) return let {
                mFilePathCallback?.onReceiveValue(arrayOf())
                mFilePathCallback = null
                KLog.e(TAG, "handleActivityResult() mFilePathCallback is null !!!")
            }
            val data = activityResult.data
            if (data?.clipData != null) {
                //有选择多个文件
                val count: Int = data.clipData!!.itemCount
                KLog.i(TAG, "handleActivityResult() url count ：  $count")
                val uris = arrayOfNulls<Uri>(count)
                var currentItem = 0
                while (currentItem < count) {
                    val fileUri: Uri = data.clipData!!.getItemAt(currentItem).uri
                    uris[currentItem] = fileUri
                    currentItem += 1
                }
                mFilePathCallback?.onReceiveValue(uris)
            } else {
                val result: Uri? = data?.data
                KLog.e(TAG, "handleActivityResult() $result")
                mFilePathCallback?.onReceiveValue(arrayOf(result))
            }
            mFilePathCallback = null
        } catch (e: Exception) {
            e.printStackTrace()
            KLog.e(TAG, "handleActivityResult() XM_Exception:$e")
        }
    }

    private fun getCurrentPageEntity() {
        mCurrentPageEntity = (arguments?.getParcelable(KEY_PAGE_ENTITY) as? PageEntity) ?: mDefaultPageEntity
        KLog.i(TAG, "getCurrentPageEntity() currentPageEntity: $mCurrentPageEntity")
        mCurrentPageEntity?.homeUrl?.let {
            mHomeUrl = it
        }
        mCurrentPageEntity?.userAgent?.let {
            mCurrentUserAgent = it
        }
    }

    private fun getCurrentUrl(): String? {
        val targetWebView = getTargetWebView() ?: return null
        // 页面加载完成后获取网页历史记录
        val historyList: WebBackForwardList = targetWebView.copyBackForwardList()
        // 获取当前页面的历史记录项
        val currentIndex: Int = historyList.currentIndex
        val currentItem: WebHistoryItem = historyList.getItemAtIndex(currentIndex) ?: return null
        return currentItem.url
    }

    private fun getUrl(target: WebView?):String?{
        val targetWebView = target ?: return null
        // 页面加载完成后获取网页历史记录
        val historyList: WebBackForwardList = targetWebView.copyBackForwardList()
        // 获取当前页面的历史记录项
        val currentIndex: Int = historyList.currentIndex
        val currentItem: WebHistoryItem = historyList.getItemAtIndex(currentIndex) ?: return null
        return currentItem.url
    }


    private fun initWebView() {
        mMainWebView = WebViewCacheHolder.INSTANCE.acquireChromeWebViewInternal(requireContext()).apply {
            TAG = "MainChromeWebViewTag"
            addWebView(this)
            if (mCurrentUserAgent.isNotEmpty()) {
                setUserAgent(mCurrentUserAgent)
            }
            mWebViewClientProxy = mWebViewClientProxyObj
            mWebViewChromeClientProxy = mWebViewChromeClientProxyObj
        }
    }

    private fun addWebView(webView: WebView) {
        val mContainer: ViewGroup = binding.webViewContainer
        mContainer.addView(webView)
    }

    override fun onResume() {
        super.onResume()
        if (!hasLoaded) {
            loadHomePage()
            hasLoaded = true
        }
        handleWebViewResume()
        if (isFullScreen) {
            mHostVm.enterFullScreen()
        }
        adapterNavigationBar(getTargetWebView())
        KLog.i(TAG, "onResume() SDK系统内核")
    }

    override fun onPause() {
        super.onPause()
        handleWebViewPause()
        mHostVm.exitFullScreen()
        cancelHiddenNavigationBar()
    }

    private fun handleWebViewResume() {
        val start = SystemClock.elapsedRealtime()
        mMainWebView?.onResume()
        for (xmProxyChromeWebView in mNewWebViewList) {
            xmProxyChromeWebView.onResume()
        }
        val diff = SystemClock.elapsedRealtime() - start
        KLog.i(TAG, "handleWebViewResume() diff: $diff")
    }

    private fun handleWebViewPause() {
        val start = SystemClock.elapsedRealtime()
        mMainWebView?.onPause()
        for (xmProxyChromeWebView in mNewWebViewList) {
            xmProxyChromeWebView.onPause()
        }
        val diff = SystemClock.elapsedRealtime() - start
        KLog.i(TAG, "handleWebViewPause() diff: $diff")
    }

    private fun handleCreateWindowProxy(
        webView: WebView?, isDialog: Boolean, isUserGesture: Boolean, message: Message?
    ): Boolean {
        val hitTestResult = webView?.hitTestResult
        val type = hitTestResult?.type
        KLog.i(TAG, "handleCreateWindowProxy() type: $type isDialog:$isDialog ,isUserGesture:$isUserGesture")
        val c = context
        return if (c != null /*&& type != WebView.HitTestResult.SRC_ANCHOR_TYPE*/) {
            val newWebView = XmProxyChromeWebView(c).apply {
                TAG = "NewChromeWebViewTag"
                if (mCurrentUserAgent.isNotEmpty()) {
                    setUserAgent(mCurrentUserAgent)
                }
                addWebView(this)
                mWebViewChromeClientProxy = mWebViewChromeClientProxyObj
                mWebViewClientProxy = mWebViewClientProxyObj
            }
            showLoading()
            mNewWebViewList.add(newWebView)
            if (message != null) {
                if (message.obj is WebView.WebViewTransport) {
                    (message.obj as WebView.WebViewTransport).webView = newWebView
                }
                message.sendToTarget()
            }
            true
        } else {
            false
        }
    }

    private fun loadUrl(url: String) {
        val count = mNewWebViewList.size
        KLog.i(TAG, "loadUrl() newWebViewCount: $count url: $url")
        if (count > 0) {
            traverseRemoveNewWebView()
        }
        mCurrentUrl = url
        mMainWebView!!.loadUrl(mCurrentUrl)

    }

    private fun checkContentState() {
        KLog.i(TAG, "checkContentState() mIsLoadFailure:$mIsLoadFailure")
        if (mIsLoadFailure) {
            showErrorState(mIsNetError)
        } else {
            showWebView()
        }
        hideLoadingView()
    }

    private fun showWebView() {
        val childCount = binding.flVideoContainer.childCount
        KLog.i(TAG, "showWebView() childCount:$childCount")
        if (childCount > 0) {
            binding.flVideoContainer.show()
        } else {
            binding.webViewContainer.show()
        }
        binding.loadError.root.hide()
    }

    private fun showErrorState(isNetError: Boolean) {
        KLog.i(TAG, "showErrorState() isNetError:$isNetError")
        binding.webViewContainer.hide()
        binding.flVideoContainer.hide()
        binding.loadError.tvMsgContent.text = if (isNetError) {
            getString(R.string.text_not_net)
        } else {
            getString(R.string.text_loading_failed)
        }
        mErrorIconRes = if (isNetError) R.drawable.icon_no_net else R.drawable.icon_load_error
        binding.loadError.ivIcon.background = binding.root.context.getDrawableRes(mErrorIconRes)
        binding.loadError.root.show()
    }

    private fun traverseRemoveNewWebView() {
        KLog.i(TAG, "traverseRemoveNewWebView() ")
        val iterator = mNewWebViewList.iterator()
        while (iterator.hasNext()) {
            val newWebView = iterator.next()
            destroyNewWebView(newWebView)
        }
    }

    private fun destroyNewWebView(newWebView: WebView?) {
        KLog.i(TAG, "destroyNewWebView() newWebView: $newWebView")
        newWebView?.let {
            hideLoadingView()
            mNewWebViewList.remove(it)
            destroyWebView(it)
        }
        if (newWebView == mFailingWebView) {
            mIsLoadFailure = false
            checkContentState()
        }
    }

    private fun openFileChooseProcess(isMulti: Boolean) {
        KLog.i(TAG, "openFileChooseProcess() ")
        val intent = Intent(Intent.ACTION_GET_CONTENT)
        intent.addCategory(Intent.CATEGORY_DEFAULT)
        intent.type = "*/*"
        if (isMulti) {
            KLog.e(TAG, "putExtra")
            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
        }
        mLaunchActivityForResult.launch(Intent.createChooser(intent, "FileChooser"))
    }

    private fun handleWebViewGoForward() {
        mIsLoadFailure = false
        if (mNewWebViewList.size > 0) {
            val lastIndex = mNewWebViewList.size - 1
            val newWebView = mNewWebViewList[lastIndex]
            KLog.i(TAG, "handleWebViewGoForward() lastIndex: $lastIndex count: ${mNewWebViewList.size}")
            if (newWebView.canGoForward()) {
                KLog.i(TAG, "handleWebViewGoForward() do New WebView forward")
                newWebView.goForward()
                safelyHandleBackAndForwardButtonState()
                return
            }
        }
        if (mMainWebView != null && mMainWebView!!.canGoForward()) {
            KLog.i(TAG, "handleWebViewGoForward() do Main WebView forward")
            mMainWebView!!.goForward()
            safelyHandleBackAndForwardButtonState()
        }
    }

    private fun handleWebViewGoBack(): Boolean {
        mIsLoadFailure = false
        if (mNewWebViewList.size > 0) {
            val lastIndex = mNewWebViewList.size - 1
            val newWebView = mNewWebViewList[lastIndex]
            KLog.i(TAG, "handleWebViewGoBack() lastIndex: $lastIndex count: ${mNewWebViewList.size}")
            if (newWebView.canGoBack()) {
                KLog.i(TAG, "handleWebViewGoBack() do New WebView back")
                newWebView.goBack()
                safelyHandleBackAndForwardButtonState()
            } else {
                KLog.i(TAG, "handleWebViewGoBack() do remove New WebView")
                destroyNewWebView(newWebView)
                safelyHandleBackAndForwardButtonState()
            }
            return true
        }
        KLog.i(TAG, "handleWebViewGoBack() do Main WebView back:${mMainWebView!!.canGoBack()}")
        if (mMainWebView != null && mMainWebView!!.canGoBack()) {
            KLog.i(TAG, "handleWebViewGoBack() do Main WebView back")
            mMainWebView!!.goBack()
            safelyHandleBackAndForwardButtonState()
            return true
        }
//        mHostVm.performHome()
        return false
    }

    private fun safelyHandleBackAndForwardButtonState() {
        try {
            if (mNewWebViewList.size > 0) {
                val lastIndex = mNewWebViewList.size - 1
                val newWebView = mNewWebViewList[lastIndex]
                KLog.i(TAG, "safelyHandleBackAndForwardButtonState() New WebView count: ${mNewWebViewList.size}")
                handleBackAndForwardButtonState(newWebView, newWebView)
                return
            }
            if (mMainWebView != null) {
                KLog.i(TAG, "safelyHandleBackAndForwardButtonState() Main WebView")
                handleBackAndForwardButtonState(mMainWebView!!, null)
            }
        } catch (t: Throwable) {
            KLog.e(TAG, "Exception: $t")
        }
    }

    private fun handleBackAndForwardButtonState(focusWebView: WebView, newWebView: WebView?) {
        KLog.i(TAG, "handleBackAndForwardButtonState() " +
                "canGoBack: " + focusWebView.canGoBack() +
                ",canGoForward: " + focusWebView.canGoForward() +
                ",newWebView: " + newWebView +
                ",currentUrl: " + focusWebView.originalUrl +
                ",url: " + focusWebView.url
        )
        if (focusWebView.canGoBack() || newWebView != null) {
            binding.btnBack.imageAlpha = ENABLE_ALPHA
            binding.btnBack.isEnabled = true
        } else {
            binding.btnBack.imageAlpha = DISABLE_ALPHA
            binding.btnBack.isEnabled = false
        }
        if (focusWebView.canGoForward()) {
            binding.btnForward.imageAlpha = ENABLE_ALPHA
            binding.btnForward.isEnabled = true
        } else {
            binding.btnForward.imageAlpha = DISABLE_ALPHA
            binding.btnForward.isEnabled = false
        }

        checkCollectState(getTargetWebView())
    }

    private fun cacheLastUrl(webView: WebView) {
        // 页面加载完成后获取网页历史记录
        val historyList = webView.copyBackForwardList() ?: return
        // 获取当前页面的历史记录项
        val currentIndex = historyList.currentIndex
        val currentItem = historyList.getItemAtIndex(currentIndex) ?: return
        val currentUrl = currentItem.originalUrl
        val url = currentItem.url
        KLog.i(TAG, """cacheLastUrl() url: $url
            |currentUrl: $currentUrl
        """.trimMargin())
        TPUtils.put(AppHolder.app, mHomeUrl, url)
    }

    private fun destroyWebView(webView: WebView?) {
        try {
            webView?.let {
                KLog.i(TAG, "destroy newWeb webView")
                it.clearHistory()
//                it.loadDataWithBaseURL(null, "", "text/html", "utf-8", null)
                val parent = it.parent
                if (parent is ViewGroup) {
                    parent.removeView(it)
                }
                it.destroy()
            }
        } catch (e: Exception) {
            e.printStackTrace()
            KLog.e(TAG, "destroyWebView() XM_Exception: $e")
        }
    }

    private fun handlePermissionRequest(
        request: PermissionRequest,
        webPermissions: Array<String>,
        context: Context
    ) {
        KLog.i(TAG, "handlePermissionRequest() webPermissions:${webPermissions.joinToString()}")
        // 过滤出系统没有给应用程序授权的权限
        val androidPermissions = mutableListOf<String>()
        webPermissions.forEach { webPermission ->
            val androidPermission = PermissionUtil.WEB_ANDROID_PERMISSION[webPermission]
            var isGrant = false
            if (!androidPermission.isNullOrEmpty()) {
                isGrant = PermissionUtil.isPermissionGrant(context, androidPermission)
                if (!isGrant) {
                    androidPermissions.add(androidPermission)
                }
            }
            KLog.i(TAG, "handlePermissionRequest() " +
                    "webPermission: $webPermission " +
                    "androidPermission: $androidPermission " +
                    ",isGrant:$isGrant")
        }
        KLog.i(TAG, "handlePermissionRequest() no authorized permissions :${androidPermissions.joinToString()}")
        if (androidPermissions.isEmpty()) {
            KLog.i(TAG, "handlePermissionRequest() all authorized")
            request.grant(webPermissions)
            return
        }
        // 先向系统申请对应未授权的权限
        requestAppPermission(androidPermissions, request, webPermissions)
    }

    private fun requestAppPermission(
        androidPermissions: MutableList<String>,
        request: PermissionRequest,
        webPermissions: Array<String>
    ) {
        XXPermissions.with(this@ChromeWebFragment)
            .permission(androidPermissions)
            .request(object : OnPermissionCallback {
                override fun onGranted(permissions: MutableList<String>, allGranted: Boolean) {
                    lifecycleScope.launch(Dispatchers.Main.immediate) {
                        handlePermissionOnGranted(allGranted, permissions, request, webPermissions)
                    }
                }

                override fun onDenied(permissions: MutableList<String>, doNotAskAgain: Boolean) {
                    lifecycleScope.launch(Dispatchers.Main.immediate) {
                        handlePermissionDenied(doNotAskAgain, permissions, request)
                    }
                }
            })
    }

    private fun handlePermissionOnGranted(
        allGranted: Boolean,
        permissions: MutableList<String>,
        request: PermissionRequest,
        webViewPermissions: Array<out String>
    ) {
        try {
            KLog.i(TAG, "handlePermissionOnGranted() " +
                    "allGranted:$allGranted ,permissions: ${permissions.joinToString()} ")
            if (!allGranted) {
                request.deny()
                promptPermissionDenied()
                return
            }
            request.grant(webViewPermissions)
        } catch (e: Exception) {
            KLog.i(TAG, "handlePermissionOnGranted() XM_Exception: $e")
            e.printStackTrace()
        }
    }

    private fun handlePermissionDenied(
        doNotAskAgain: Boolean,
        permissions: MutableList<String>,
        request: PermissionRequest
    ) {
        try {
            KLog.i(TAG, "handlePermissionDenied() doNotAskAgain:$doNotAskAgain ,permissions:$permissions")
            request.deny()
            promptPermissionDenied()
        } catch (e: Exception) {
            e.printStackTrace()
            KLog.e(TAG, "handlePermissionDenied() XM_Exception: $e")
        }
    }

    private fun promptPermissionDenied() {
        KLog.e(TAG, "promptPermissionDenied() 权限被拒绝，该功能需要相关权限，请授予相关权限")
    }

    private fun showPromptDialog(message: String?, result: JsResult?) {
        XmPromptDialog()
            .setup {
                it.mContentText = message
            }.onPositiveButton {
                result?.confirm()
            }.showDialog(mImitateDialogHelper)
    }

    private fun showSelectDialog(message: String?, result: JsResult?) {
        XmSelectDialog()
            .setup {
                it.mContentText = message
            }.onPositiveButton {
                result?.confirm()
            }.onNegativeButton {
                result?.cancel()
            }.showDialog(mImitateDialogHelper)
    }

    override fun onDestroyView() {
        super.onDestroyView()
        hasLoaded = false
    }

    override fun onDestroy() {
        super.onDestroy()
        destroyAllNewWeb()
        destroyWebView(mMainWebView)
        WebViewCacheHolder.INSTANCE.prepareWebView()
    }

    private fun destroyAllNewWeb() {
        mNewWebViewList.forEach {
            destroyWebView(it)
        }
    }

    private fun showLoading() {
        binding.layoutWebLoading.root.show()
        binding.layoutWebLoading.pbLoading.show()
        binding.loadError.root.hide()
    }

    override fun onBackPressed(): Boolean {
        val size = mImitateDialogHelper.mDialogs.size
        KLog.i(TAG, "onBackPressed() size:$size")
        return size > 0 || handleWebViewGoBack()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        mImitateDialogHelper.onSaveInstanceState(outState)
    }

    open fun setNeedMatchParent(fullScreen: Boolean) {

    }

    private fun showSSLErrorUserOptionDialog(
        handler: SslErrorHandler?,
        view: WebView?
    ) {
        KLog.i(TAG, "showSSLErrorUserOptionDialog() mIsLoadFailure:$mIsLoadFailure")
        // 如果已经显示异常界面了，就不要再显示选择浮窗了，直接走重新加载吧
        if (mIsLoadFailure) return
        XmSelectDialog().setup {
            it.mContentText =
                getString(R.string.text_ssl_error_tips)
        }.onPositiveButton {
            handler?.proceed()
        }.onNegativeButton {
            handler?.cancel()
            handleReceivedError(true, view?.url, view)
        }.showDialog(mImitateDialogHelper)
    }


    private fun hideLoadingView() {
        binding.layoutWebLoading.pbLoading.hide()
        binding.layoutWebLoading.root.hide()
    }

    companion object {

        private const val KEY_PAGE_ENTITY = "key_page_entity_chrome"
        fun newWebFragment(pageEntity: PageEntity): ChromeWebFragment {
            val x5WebFragment = ChromeWebFragment()
            val args = Bundle()
            args.putParcelable(KEY_PAGE_ENTITY, pageEntity)
            x5WebFragment.arguments = args
            return x5WebFragment
        }
    }

}